/*****************************************************************************\
FILE    : Ug3DSection.c
PURPOSE : Pro/TOOLKIT User Guide Examples related to 3d sections
HISTORY..
DATE      BUILD   AUTHOR    MODIFICATIONS
04-Dec-97 H-02-02 Philippe  $$1    Created from old userguide code
10-Dec-97 H-03-31 Philippe  $$2    add includes
30-Dec-97 H-03-33 KS	    $$3	   Initialized trf matrix to NULL 	
02-Mar-99 I-03-03 jeff      $$4    Wrapped PI's define inside ifndef
29-May-02 J-03-27 JCN       $$5    Added section replacement
08-Jul-02 J-03-29 SMK       $$6    Added UserSectionPointBuild
27-Jul-02 J-03-30 SMK       $$7    Added initialization for static variables
10-Aug-02 J-03-31 SMK       $$8    Added Sweep section creation
18-Sep-02 J-03-34 JCN       $$9    Added UserUtilItemSelect utility
24-Sep-02 J-03-34+ JCN      $$10   Set message file in some utilities
06-Oct-03 K-01-16 JCN       $$11   Added include
15-May-07 L-01-31 VSA       $$12   Replaced lib calls with Unicode wrapper calls
\*****************************************************************************/
#include <ProToolkit.h>
#include <ProMdl.h>
#include <ProElement.h>
#include <ProFeature.h>
#include <ProFeatType.h>
#include <ProFeatForm.h>
#include <ProModFeat.h>
#include <ProExtrude.h>
#include <ProSection.h>
#include <ProSelection.h>
#include <ProStdSection.h>
#include <ProSecdim.h>
#include <ProUtil.h>
#include <TestError.h>
#include <PTApplsUnicodeUtils.h>
#include <math.h>
#include <UtilMath.h>
/*---------------------------External Functions------------------------------*/
extern void ProUtil2DPointTrans();
extern double *ProUtilLineLineX();

/*--------------------------Globlal Definition ------------------------------*/
typedef struct mtrx_data{ 
	ProVector x_axis[2];
	ProVector y_axis[2];
	ProMatrix sec_trf; 
	ProMatrix sk_mtrx; 
	ProSelection sk_plane;
	double angle;
}Matrix_data;

static wchar_t msgfile[PRO_NAME_SIZE];

ProSelection *temp2 = NULL;
ProSelection *temp1 = NULL;

#ifndef PI
# define PI 3.141592
#endif
/* --------------------------Function Prototypes ----------------------------*/
ProError UserSelectSketchPlaneRefs(ProSelection **sketch_refs);
ProError UserSelectProjectionEntities(ProSelection **proj_refs);
ProError UserSelectOffsetDistances(double *offset_vals);
ProError UserCreateTrfMatrix(Matrix_data *m_data);
ProError UserSecerrorPrint ( ProWSecerror *section_errors ); 
ProError UserSweepSectionAdd ( ProSection ); 
ProError UserSweepSpineAdd ( ProSection , ProSelection * ); 
ProError UserSectionCircleToEllipseReplace (ProSection sect_handle);



/* =============================================================== *\
   Function: UsetUtilItemSelect
   Purpose: Selection utility for feature create examples
\* =============================================================== */
ProError UserUtilItemSelect (char* filter_string, char* message,
								int* id, ProType* type)
{
	ProError err;
	ProSelection* sels;
	ProModelitem item;
	int n_sels;

	err = PRO_TK_GENERAL_ERROR;
    do 
	{
		ProMessageDisplay (msgfile, message);

		err = ProSelect (filter_string, 1, NULL, NULL, NULL, NULL, &sels, &n_sels);

		if (err == PRO_TK_USER_ABORT || err == PRO_TK_PICK_ABOVE)
				return err;
	} while (err != PRO_TK_NO_ERROR);

	err = ProSelectionModelitemGet (sels[0], &item);

	*id = item.id;
	*type = item.type;

	return PRO_TK_NO_ERROR;	
}

/* =============================================================== *\
   Function: UserSectionBuild(ProSection section, ProSelection *sketch_refs)
   Purpose: Creates 3D section 
\* =============================================================== */
ProError UserSectionBuild(ProSection section, ProSelection *sketch_refs)
{

  ProSelection *proj_ents;
  int status, i, num_errors, err_counter, proj_ids[2];
  int ctr_line_id, rt_line_id, lt_line_id, top_line_id, btm_line_id;
  int upper_arc_id, lower_arc_id, ent_id[1], c_ent_id[2], proj_ent_id[2];
  int ll_dim_id, tl_dim_id, ua_dim_id, la_dim_id, cl_dim_id, proj_dim_id[2];
  ProWSecerror sec_errors;
  Pro2dLinedef line;
  Pro2dClinedef c_line;
  Pro2dLinedef *left_linedef, *btm_linedef;
  ProSectionPointType pt_type[1], proj_pt_type[2];
  Pro2dArcdef arc;
  Pro2dPnt place_pnt;
  ProMsg wmsg;
  char msg[PRO_PATH_SIZE];
  double offsets[2];
  Matrix_data matrix_data;

  ProStringToWstring(msgfile, "msg_ug3dsketch.txt");


/* =============================================================== *\
   	Obtain projection entity handles as ProSelection structures
\* =============================================================== */

  status = UserSelectProjectionEntities(&proj_ents);
  ERROR_CHECK("UserSelectrojectionEntities", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
    Project reference edges onto section
\* =============================================================== */

  for (i = 0; i < 2; i++)
    {
      status = ProSectionEntityFromProjection(section, proj_ents[i], &proj_ids[i]);
      ERROR_CHECK("ProSectionEntityFromProjection", "UserSectionBuild", status);
      if (status != PRO_TK_NO_ERROR) return status;
    }

/* =============================================================== *\
    Create section csys from edges, and obtion transformation 
	matrix between sketch plane csys and section csys
\* =============================================================== */

  status = ProSectionEntityGet(section, proj_ids[0], (Pro2dEntdef **)&btm_linedef);
  ERROR_CHECK("ProSectionEntityGet", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

  for (i = 0; i < 2; i++)
    {
      matrix_data.x_axis[0][i] = btm_linedef->end1[i];
      matrix_data.x_axis[1][i] = btm_linedef->end2[i];
      matrix_data.x_axis[i][2] = 0.0; 
    }
	
  status = ProSectionEntityGet(section, proj_ids[1], (Pro2dEntdef **)&left_linedef);
  ERROR_CHECK("ProSectionEntityGet", "UserSectionBuild", status);
  if ( status != PRO_TK_NO_ERROR )
    return status; 
	
  for (i = 0; i < 2; i++)
    {
      matrix_data.y_axis[0][i] = left_linedef->end1[i]; 
      matrix_data.y_axis[1][i] = left_linedef->end2[i];
      matrix_data.y_axis[i][2] = 0.0; 
    }


  status = ProSectionLocationGet(section, matrix_data.sk_mtrx);
  ERROR_CHECK("ProSectionLocationGet", "UserCreateTrfMatrix", status);
  if (status != PRO_TK_NO_ERROR) return status;

  status = ProSelectionCopy(sketch_refs[0], &(matrix_data.sk_plane));
  ERROR_CHECK("ProSelectionCopy", "UserSectionBuild", status) ;
  if (status != PRO_TK_NO_ERROR) return status;

  status = UserCreateTrfMatrix(&matrix_data);
  ERROR_CHECK("UseCreateTrfMatrix", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   	Obtain offset values from projection entities
\* =============================================================== */

  status = UserSelectOffsetDistances(offsets);
  ERROR_CHECK("UserSelectOffsetDistances", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   		Add center line ...
\* =============================================================== */
  c_line.type = PRO_2D_CENTER_LINE;
  c_line.end1[0] = 0.0;
  c_line.end1[1] = 0.0;
  c_line.end2[0] = 0.0;
  c_line.end2[1] = 1.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, c_line.end1, c_line.end1);
  ProUtil2DPointTrans(matrix_data.sec_trf, c_line.end2, c_line.end2);

  status = ProSectionEntityAdd(section, (Pro2dEntdef*)&c_line, &ctr_line_id);
  ERROR_CHECK("UserSectionEntityAdd - 1", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;
		
/* =============================================================== *\
   		Add left vertical line ...
\* =============================================================== */
  line.type = PRO_2D_LINE;
  line.end1[0] = offsets[1];
  line.end1[1] = offsets[0];
  line.end2[0] = offsets[1];
  line.end2[1] = offsets[0] + 50.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, line.end1, line.end1);
  ProUtil2DPointTrans(matrix_data.sec_trf, line.end2, line.end2);

  status = ProSectionEntityAdd(section, (Pro2dEntdef*)&line, &lt_line_id);
  ERROR_CHECK("UserSectionEntityAdd - 1", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   		Add top line ...
\* =============================================================== */
  line.type = PRO_2D_LINE;
  line.end1[0] = offsets[1];
  line.end1[1] = offsets[0] + 50.0;
  line.end2[0] = offsets[1] + 25.0;
  line.end2[1] = offsets[0] + 50.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, line.end1, line.end1);
  ProUtil2DPointTrans(matrix_data.sec_trf, line.end2, line.end2);
	
  status = ProSectionEntityAdd(section, (Pro2dEntdef*)&line, &top_line_id);
  ERROR_CHECK("UserSectionEntityAdd - 2", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   		Add upper arc ...
\* =============================================================== */
  arc.type = PRO_2D_ARC;
  arc.center[0] = offsets[1] + 40.0; 
  arc.center[1] = offsets[0] + 50.0;
  arc.start_angle =  PI + matrix_data.angle;
  arc.end_angle = 1.5*PI + matrix_data.angle;
  arc.radius = 15.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, arc.center, arc.center);

  status = ProSectionEntityAdd(section, (Pro2dEntdef*)&arc, &upper_arc_id);
  ERROR_CHECK("UserSectionEntityAdd - 3", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   		Add right vertical line ...
\* =============================================================== */
  line.type = PRO_2D_LINE;
  line.end1[0] = offsets[1] + 40.0;
  line.end1[1] = offsets[0] + 35.0;
  line.end2[0] = offsets[1] + 40.0;
  line.end2[1] = offsets[0] + 10.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, line.end1, line.end1);
  ProUtil2DPointTrans(matrix_data.sec_trf, line.end2, line.end2);

  status = ProSectionEntityAdd(section, (Pro2dEntdef*)&line, &rt_line_id);
  ERROR_CHECK("UserSectionEntityAdd - 4", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   		Add lower arc ...
\* =============================================================== */
  arc.type = PRO_2D_ARC;
  arc.center[0] = offsets[1] + 40.0; 
  arc.center[1] = offsets[0];
  arc.start_angle = 0.5*PI + matrix_data.angle;
  arc.end_angle = PI + matrix_data.angle; 
  arc.radius = 10.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, arc.center, arc.center);

  status = ProSectionEntityAdd(section, (Pro2dEntdef*)&arc, &lower_arc_id);
  ERROR_CHECK("UserSectionEntityAdd - 5", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   		Add bottom line ...
\* =============================================================== */
  line.type = PRO_2D_LINE;
  line.end1[0] = offsets[1] + 30.0;
  line.end1[1] = offsets[0];
  line.end2[0] = offsets[1];
  line.end2[1] = offsets[0];

  ProUtil2DPointTrans(matrix_data.sec_trf, line.end1, line.end1);
  ProUtil2DPointTrans(matrix_data.sec_trf, line.end2, line.end2);

  status = ProSectionEntityAdd(section, (Pro2dEntdef*)&line, &btm_line_id);
  ERROR_CHECK("UserSectionEntityAdd - 6", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   		Add dimension for left line
\* =============================================================== */

  ent_id[0] = lt_line_id;
  pt_type[0] = PRO_ENT_WHOLE;
  place_pnt[0] = offsets[1] - 2.0;
  place_pnt[1] = offsets[0] + 25.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, place_pnt, place_pnt);

  status = ProSecdimCreate(section, ent_id, pt_type, 1, PRO_TK_DIM_LINE, place_pnt, &ll_dim_id); 
  ERROR_CHECK("ProSecdimCreate - 1", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   	Add dimension for top line
\* =============================================================== */

  ent_id[0] = top_line_id;
  pt_type[0] = PRO_ENT_WHOLE;
  place_pnt[0] = offsets[1] + 13.0;
  place_pnt[1] = offsets[0] + 52.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, place_pnt, place_pnt);

  status = ProSecdimCreate(section, ent_id, pt_type, 1, PRO_TK_DIM_LINE, place_pnt, &tl_dim_id); 
  ERROR_CHECK("ProSecdimCreate - 2", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   	Add dimension for upper arc
\* =============================================================== */

  ent_id[0] = upper_arc_id;
  pt_type[0] = PRO_ENT_WHOLE;
  place_pnt[0] = offsets[1] + 42.0;
  place_pnt[1] = offsets[0] + 42.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, place_pnt, place_pnt);

  status = ProSecdimCreate(section, ent_id, pt_type, 1, PRO_TK_DIM_RAD, place_pnt, &ua_dim_id); 
  ERROR_CHECK("ProSecdimCreate - 3", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   	Add dimension for lower arc
\* =============================================================== */

  ent_id[0] = lower_arc_id;
  pt_type[0] = PRO_ENT_WHOLE;
  place_pnt[0] = offsets[1] +42.0;
  place_pnt[1] = offsets[0] + 5.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, place_pnt, place_pnt);

  status = ProSecdimCreate(section, ent_id, pt_type, 1, PRO_TK_DIM_RAD, place_pnt, &la_dim_id); 
  ERROR_CHECK("ProSecdimCreate - 4", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

/* =============================================================== *\
   	Add section dimension between center line and left line
\* =============================================================== */
	
  c_ent_id[0] = ctr_line_id;
  c_ent_id[1] = lt_line_id;
  proj_pt_type[0] = PRO_ENT_WHOLE;	
  proj_pt_type[1] = PRO_ENT_WHOLE;	
  place_pnt[0] = offsets[1] - 2.0;
  place_pnt[1] = offsets[0] + 15.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, place_pnt, place_pnt);

  status = ProSecdimCreate(section, c_ent_id, proj_pt_type, 2, PRO_TK_DIM_LINE_LINE, place_pnt, &cl_dim_id);
  ERROR_CHECK("ProSecdimCreate - 5", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

  status = ProSecdimValueSet(section, cl_dim_id, offsets[1]);
  ERROR_CHECK("ProSecdimValueSet", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

  /* =============================================================== *\
   	Add section dimension between center line and left projection
	entity
\* =============================================================== */

  proj_ent_id[0] = ctr_line_id;
  proj_ent_id[1] = proj_ids[1];
  proj_pt_type[0] = PRO_ENT_WHOLE;	
  proj_pt_type[1] = PRO_ENT_WHOLE;	
  place_pnt[0] = -2.0;
  place_pnt[1] = 15.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, place_pnt, place_pnt);

  status = ProSecdimCreate(section, proj_ent_id, proj_pt_type, 2, PRO_TK_DIM_LINE_LINE, place_pnt, &proj_dim_id[0]);
  ERROR_CHECK("ProSecdimCreate - 5", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

  status = ProSecdimValueSet(section, proj_dim_id[0], 0.0);
  ERROR_CHECK("ProSecdimValueSet", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

  /* =============================================================== *\
   	Add section dimension between bottom proj ent and bottom line
\* =============================================================== */
	
  proj_ent_id[0] = btm_line_id;
  proj_ent_id[1] = proj_ids[0];
  proj_pt_type[0] = PRO_ENT_WHOLE;	
  proj_pt_type[1] = PRO_ENT_WHOLE;	
  place_pnt[0] = offsets[1] + 20.0;
  place_pnt[1] = offsets[0] - 3.0;

  ProUtil2DPointTrans(matrix_data.sec_trf, place_pnt, place_pnt);

  status = ProSecdimCreate(section, proj_ent_id, proj_pt_type, 2, PRO_TK_DIM_LINE_LINE, place_pnt, &proj_dim_id[1]);
  ERROR_CHECK("ProSecdimCreate - 6", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

  status = ProSecdimValueSet(section, proj_dim_id[1], offsets[0]);
  ERROR_CHECK("ProSecdimValueSet", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

  /* =============================================================== *\
   		Solve and regenerate the section
  \* =============================================================== */

  status = ProSecerrorAlloc(&sec_errors);
  ERROR_CHECK("ProSecerrorAlloc", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR) return status;

  status = ProSectionSolve(section, &sec_errors);
  if (status != 0)
    {
      UserSecerrorPrint (  &sec_errors );
      return status; 
    }

  status = ProSectionRegenerate(section, &sec_errors);
  if (status != 0)
    {
      UserSecerrorPrint (  &sec_errors );
      return status; 
    }
	
  status = ProSelectionFree(&(matrix_data.sk_plane));
  ERROR_CHECK("ProSelectionFree", "UserSectionBuild", status);

  free(temp1);
  free(temp2);

  temp1 = NULL;
  temp2 = NULL; 

  return(status);
}


/* =============================================================== *\
   Function: UserSelectSketchPlaneRefs
   Purpose: Select references for sketch plane and orientation plane
\* =============================================================== */

ProError UserSelectSketchPlaneRefs(ProSelection **sketch_refs)
{
  ProSelection *sel;
  int num_sel;
  ProError status;

  if (temp1 == NULL)
    temp1 = (ProSelection *)calloc(2, sizeof(ProSelection)); 

  ProStringToWstring(msgfile, "msg_ug3dsketch.txt");

  status = ProMessageDisplay(msgfile, "USER Select sketch plane");
  ERROR_CHECK("ProMessageDisplay", "UserSectionBuild", status);
  status = ProSelect("surface", 1, NULL, NULL, NULL, NULL, &sel, &num_sel);
  ERROR_CHECK("ProSelect", "UserSectionBuild", status);
  status = ProSelectionCopy(sel[0],&temp1[0]);
  ERROR_CHECK("ProSelectionCopy", "UserSectionBuild", status);

  status = ProMessageDisplay(msgfile, "USER Select top plane for orientation");
  ERROR_CHECK("ProMessageDisplay", "UserSectionBuild", status);
  status = ProSelect("surface", 1, NULL, NULL, NULL, NULL, &sel, &num_sel);
  ERROR_CHECK("ProSelect", "UserSectionBuild", status);
  status = ProSelectionCopy(sel[0], &temp1[1]);
  ERROR_CHECK("ProSelectionCopy", "UserSectionBuild", status);

  *sketch_refs = temp1; 

  return(status);
}


/* =============================================================== *\
   Function: UserSelectProjectionEntities
   Purpose: Select projection entity references from existing geometry
\* =============================================================== */

ProError UserSelectProjectionEntities(ProSelection **proj_refs)
{

  ProSelection *sel;
  int num_sel;
  ProError status;

  if (temp2== NULL)
    temp2= (ProSelection *)calloc(2, sizeof(ProSelection));
  /* =============================================================== *\
     Prompt user to select reference geometry
  \* =============================================================== */
  ProStringToWstring(msgfile, "msg_ug3dsketch.txt");

  status = ProMessageDisplay(msgfile, 
		"USER Select first projection reference (bottom edge of sketch plane)");
  ERROR_CHECK("ProMessageDisplay", "UserSectionBuild", status);
  status = ProSelect("edge", 1, NULL, NULL, NULL, NULL, &sel, &num_sel);
  ERROR_CHECK("ProSelect", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR || num_sel < 1)
    return(status);
  status = ProSelectionCopy(sel[0], &temp2[0]);
  ERROR_CHECK("ProSelectionCopy", "UserSectionBuild", status);
	
  status = ProMessageDisplay(msgfile, 
		"USER Select second projection reference (left edge of sketch plane)");
  ERROR_CHECK("ProMessageDisplay", "UserSectionBuild", status);
  status = ProSelect("edge", 1, NULL, NULL, NULL, NULL, &sel, &num_sel);
  ERROR_CHECK("ProSelect", "UserSectionBuild", status);
  if (status != PRO_TK_NO_ERROR || num_sel < 1)
    return(status);
  status = ProSelectionCopy(sel[0], &temp2[1]);
  ERROR_CHECK("ProSelectionCopy", "UserSectionBuild", status);

  *proj_refs = temp2;

  return(status);

}


ProError UserSelectOffsetDistances(double *offset_vals)
{

  ProError status;

  ProStringToWstring(msgfile, "msg_ug3dsketch.txt");

  status = ProMessageDisplay(msgfile, 
		"USER Enter offset distance from first projection reference");
  ERROR_CHECK("ProMessageDisplay", "UserSelectOffsetDistances", status);
  status = ProMessageDoubleRead(NULL, &offset_vals[0]);
  ERROR_CHECK("ProMessageDoubleRead", "UserSelectOffsetDistances", status);


  status = ProMessageDisplay(msgfile, 
		"USER Enter offset distance from second projection reference");
  ERROR_CHECK("ProMessageDisplay", "UserSelectOffsetDistances", status);
  status = ProMessageDoubleRead(NULL, &offset_vals[1]);
  ERROR_CHECK("ProMessageDoubleRead", "UserSelectOffsetDistances", status);

  return(status);

}

ProError UserCreateTrfMatrix(Matrix_data *m_data)
{

  ProPoint3d origin; 
  double sel_pnt[3], proj_sel_pnt[3], sel_vect[3]; 
  double x_plane[3];
  ProVector x, y, sk_plane_norm;
  ProVector d1[2], d2[2], norm;
  int status;
  ProMatrix inv_sk_mtrx;
  ProModelitem sk_modelitem;
  ProSurface sk_surf;
  ProUvParam sk_param;
  /* =============================================================== *\
   	Project point selected on sketch plane onto section
\* =============================================================== */

  ProUtilMatrixInvert(m_data->sk_mtrx, inv_sk_mtrx);

  status = ProSelectionUvParamGet(m_data->sk_plane, sk_param);
  ERROR_CHECK("ProSelectionUvParamGet", "UserCreateTrfMatrix", status);
  status = ProSelectionModelitemGet(m_data->sk_plane, &sk_modelitem);
  ERROR_CHECK("ProSelectionModelitemGet", "UserCreateTrfMatrix", status);
  status = ProGeomitemToSurface((ProGeomitem *)&sk_modelitem, &sk_surf);
  ERROR_CHECK("ProGeomitemToSurface", "UserCreateTrfMatrix", status);
  status = ProSurfaceXyzdataEval(sk_surf, sk_param, sel_pnt, d1, d2, norm);
  ERROR_CHECK("ProSurfaceXyzdataEval", "UserCreateTrfMatrix", status);

  ProUtilPointTrans(inv_sk_mtrx, sel_pnt, proj_sel_pnt);
  proj_sel_pnt[2] = 0.0;

  /* =============================================================== *\
  	Create x and y vectors of transformation matrix such that 
	selected point on sketch plane is in first quadrant
\* =============================================================== */

  ProUtilLineLineX(m_data->x_axis, m_data->y_axis, origin);

  ProUtilVectorDiff(proj_sel_pnt, origin, sel_vect);
  sel_vect[2] = 0.0;
  ProUtilVectorNormalize(sel_vect, sel_vect);

  ProUtilVectorDiff(m_data->x_axis[0], m_data->x_axis[1], x);
  ProUtilVectorNormalize(x, x);

  ProUtilVectorDiff(m_data->y_axis[0], m_data->y_axis[1], y);
  ProUtilVectorNormalize(y, y);	
	
/* =========  Selected point should be in first quadrant  ======= */

  if ((ProUtilVectorDot(x,sel_vect)) < 0.0)
    ProUtilVectorScale(-1.0, x, x);

  if ((ProUtilVectorDot(y,sel_vect)) < 0.0)
    ProUtilVectorScale(-1.0, y, y);

/* ========= Make sure surface normal is properly oriented   ======= */
/* ========= with respect to x and y   ============================= */


  ProUtilVectorCross(x, y, sk_plane_norm);
  ProUtilVectorTrans(m_data->sk_mtrx, sk_plane_norm, sk_plane_norm);
  ProUtilMatrixCopy(NULL, m_data->sec_trf);

  if ((ProUtilVectorDot(sk_plane_norm, m_data->sk_mtrx[2])) < 0.0)
    {
      ProUtilVectorCopy(y, m_data->sec_trf[0]);
      ProUtilVectorCopy(x, m_data->sec_trf[1]);
      ProUtilVectorCopy(NULL, m_data->sec_trf[2]);
      ProUtilVectorCopy(origin, m_data->sec_trf[3]);
    }

  else
    {
      ProUtilVectorCopy(x, m_data->sec_trf[0]);
      ProUtilVectorCopy(y, m_data->sec_trf[1]);
      ProUtilVectorCopy(NULL, m_data->sec_trf[2]);
      ProUtilVectorCopy(origin, m_data->sec_trf[3]);
    }
		
  m_data->sec_trf[2][2] = m_data->sec_trf[3][3] = 1.0;

/* =============================================================== *\
		Calculate rotation angle  	
\* =============================================================== */
  x_plane[0] = 1.0;
  x_plane[1] = x_plane[2] = 0.0;
  ProUtilVectorCross(x_plane, m_data->sk_mtrx[0], norm);
  ProUtilVectorCross(m_data->sec_trf[0], m_data->sec_trf[1], sk_plane_norm);
  m_data->angle = fabs(acos(ProUtilVectorDot(x_plane, m_data->sec_trf[0])));
  if (ProUtilVectorDot(norm, sk_plane_norm) < 0.0)
    m_data->angle *= -1.0;

  return(status);

}

/*====================================================================*\
FUNCTION: UserSectionReplace
PURPOSE:  Menu button action function for section replacement
\*====================================================================*/
ProError UserSectionReplace ()
{
  ProError status;
  ProSelection* sel_array;
  int n_sels;
  ProFeature feat;
  ProElement sk_elem_tree;
  ProElempath sk_elem_path;
  ProElempathItem elem_path_data [3];
  ProElement sk_elem;
  ProValue value;
  ProValueData value_data;
  ProSection sect_handle;
  ProFeatureCreateOptions options [] = {PRO_FEAT_CR_DO_NOT_DISPLAY};
  int n_opts = 1;
  ProErrorlist redef_errs;
  
  elem_path_data [0].type = PRO_ELEM_PATH_ITEM_TYPE_ID;
  elem_path_data [0].path_item.elem_id = PRO_E_STD_SECTION;
  elem_path_data [1].type = PRO_ELEM_PATH_ITEM_TYPE_ID;
  elem_path_data [1].path_item.elem_id = PRO_E_SKETCHER;
  
  status = ProSelect ("feature", 1, NULL, NULL, NULL, NULL, &sel_array, &n_sels);
  ERROR_CHECK ("ProSelect", "UserSectionReplace",  status);
  if (status != PRO_TK_NO_ERROR)
	return status;

  status = ProSelectionModelitemGet (sel_array [0], &feat);
  ERROR_CHECK ("ProSelectionModelitemGet", "UserSectionReplace",  status);

  /*--------------------------------------------------------------------*\
		Find the sketch handle from the feature handle.
  \*--------------------------------------------------------------------*/
  status = ProFeatureElemtreeCreate (&feat, &sk_elem_tree);
  ERROR_CHECK ("ProFeatureElemtreeCreate()", "UserSectionReplace",  status);
  
  status = ProElempathAlloc (&sk_elem_path);
  ERROR_CHECK ("ProElempathAlloc()", "UserSectionReplace",  status);
  
  status = ProElempathDataSet (sk_elem_path, elem_path_data, 2);
  ERROR_CHECK ("ProElempathDataSet()", "UserSectionReplace",  status);
  
  status = ProElemtreeElementGet (sk_elem_tree, sk_elem_path, 
                                  &sk_elem);
  ERROR_CHECK ("ProElemtreeElementGet()", "UserSectionReplace",  status);
  
  ProElempathFree (&sk_elem_path);
  
  status = ProElementValueGet (sk_elem, &value);
  ERROR_CHECK ("ProFeatureElemValueGet()", "UserSectionReplace",  status);
  
  status = ProValueDataGet (value, &value_data);
  ERROR_CHECK ("ProValueDataGet()", "UserSectionReplace",  status);
  
  sect_handle = (ProSection) value_data.v.p;

  /*--------------------------------------------------------------------*\
		Replace the section entity
  \*--------------------------------------------------------------------*/
  status = UserSectionCircleToEllipseReplace (sect_handle);
  ERROR_CHECK ("UserSectionCircleToEllipseReplace", "UserSectionReplace",  status);

  if (status == PRO_TK_NO_ERROR)
  {
	status = ProFeatureRedefine (NULL, 
                                   &feat,
                                   sk_elem_tree,
                                   options, 
                                   n_opts,
                                   &redef_errs);
	ERROR_CHECK ("ProFeatureRedefine()", "UserSectionReplace",  status);

	ProWindowRepaint (-1);
  }
 
  return (1);
}

/*====================================================================*\
FUNCTION: UserSectionCircleToEllipseReplace
PURPOSE:  Replace a circular sketch entity with ellipse entity
\*====================================================================*/
ProError UserSectionCircleToEllipseReplace (ProSection sect_handle)
{
  ProError status;
  ProBoolean is_proj;
  ProIntlist id_array;
  int array_size, i, replace_id;
  Pro2dEntdef* ent_def;
  
  Pro2dEllipsedef ellipse_def;
  Pro2dCircledef* circle_def;
  int project_1 = -1;
  int project_2 = -1;
  int circle_id = -1;
  int ellipse_id;

  int ent_ids [2];
  ProSectionPointType pnt_types [2];
  Pro2dPnt place_pnt = {0.0, 0.0};
  int dim_id;
  
  ProWSecerror sec_errs;
 
/*--------------------------------------------------------------------*\
	Get existing entities (needed to do the replacement)
\*--------------------------------------------------------------------*/
  status = ProSectionEntityIdsGet (sect_handle, &id_array, &array_size);
  ERROR_CHECK ("ProSectionEntityIdsGet()", "UserSectionCircleToEllipseReplace", status);
  
  for (i = 0; i < array_size; i++)
    {
      status = ProSectionEntityGet (sect_handle, id_array[i], &ent_def);
   
	  if (ent_def->type == PRO_2D_LINE)
	  {
		/*--------------------------------------------------------------------*\
			Check for reference entity
		\*--------------------------------------------------------------------*/
		status = ProSectionEntityIsProjection (sect_handle, id_array [i], &is_proj);
		
		if (!is_proj)
			return /*PRO_TK_UNAV_SEC;*/13;
		else
		{
			if (project_1 == -1)
				project_1 = id_array [i];
			else if (project_2 == -1)
				project_2 = id_array [i];
			else
				return /*PRO_TK_UNAV_SEC;*/14;
		}
	  }
	  else if (ent_def->type == PRO_2D_CIRCLE)
	  {
		circle_id = id_array [i];
		circle_def = (Pro2dCircledef*)ent_def;
	  }		
	  else
		return /*PRO_TK_UNAV_SEC;*/15;
    }
  if (project_1 == -1 || project_2 == -1 || circle_id == -1)
	  return /*PRO_TK_UNAV_SEC;*/16;

  ProArrayFree ((ProArray*)&id_array);
 
/*--------------------------------------------------------------------*\
	Add the new entity (ellipse)
\*--------------------------------------------------------------------*/
  ellipse_def.type = PRO_2D_ELLIPSE;
  memcpy (ellipse_def.origin, circle_def->center, sizeof (Pro2dPnt));
  ellipse_def.x_radius = circle_def->radius * 1.2;
  ellipse_def.y_radius = circle_def->radius * 0.8;
  
  status = ProSectionEntityAdd (sect_handle, (Pro2dEntdef*)&ellipse_def, &ellipse_id);            
  ERROR_CHECK ("ProSectionEntityAdd()", "UserSectionCircleToEllipseReplace", status);

/*--------------------------------------------------------------------*\
	Manually dimension to new entity to the reference entities
	 -- The replacement process will remove projected entities not currently in use.
	 -- Adding dimensions from the replacement ellipse to the projected entities
	       forces the entities to remain.
\*--------------------------------------------------------------------*/
  ent_ids [0] = project_1;
  ent_ids [1] = ellipse_id; 
  pnt_types [0] = PRO_ENT_WHOLE;
  pnt_types [1] = PRO_ENT_CENTER;
    
  status = ProSecdimCreate (sect_handle, ent_ids, pnt_types, 2, PRO_TK_DIM_LINE_POINT, place_pnt, &dim_id);
  ERROR_CHECK ("ProSecdimCreate()", "UserSectionCircleToEllipseReplace", status);

  ent_ids [0] = project_2;
  status = ProSecdimCreate (sect_handle, ent_ids, pnt_types, 2, PRO_TK_DIM_LINE_POINT, place_pnt, &dim_id);
  ERROR_CHECK ("ProSecdimCreate()", "UserSectionCircleToEllipseReplace", status);
 
/*--------------------------------------------------------------------*\
	Perform the replacement
\*--------------------------------------------------------------------*/
  status = ProSectionEntityReplace (sect_handle, circle_id, 
                                    ellipse_id);
  ERROR_CHECK ("ProSectionEntityReplace()", "UserSectionCircleToEllipseReplace", status);

/*--------------------------------------------------------------------*\
	Finish up dimensioning (x- and y- radius dimensions)
\*--------------------------------------------------------------------*/
  status = ProSectionAutodim (sect_handle, &sec_errs);
  ERROR_CHECK ("ProSectionAutodim()", "UserSectionCircleToEllipseReplace", status);

  if ( status != PRO_TK_NO_ERROR )
    {
      UserSecerrorPrint (  &sec_errs );
      return status; 
    }

  status = ProSectionRegenerate (sect_handle, &sec_errs);
  ERROR_CHECK ("ProSectionRegenerate()", "UserSectionCircleToEllipseReplace", status);

  if ( status != PRO_TK_NO_ERROR )
    {
      UserSecerrorPrint (  &sec_errs );
    }

  return (status);
}

/* =============================================================== *\
   Function: UserSectionPointBuild(ProSection section, ProSelection *sketch_refs)
   Purpose:  Creates a 3D Section consisting of Points
\* =============================================================== */
ProError UserSectionPointBuild(ProSection section, ProSelection *sketch_refs)
{
  int 		status, i, num_errors, err_counter, proj_ids[2];
  int 		point_id; 
  double 	offsets[2];
  char 		msg[PRO_PATH_SIZE];
  ProMsg 	wmsg;

  Matrix_data 	matrix_data;

  ProSelection 	*proj_ents;
  ProWSecerror 	sec_errors;
  Pro2dPointdef point;
  Pro2dLinedef  *btm_linedef, *left_linedef;
  
  ProStringToWstring(msgfile, "msg_ug3dsketch.txt");
  
/* =============================================================== *\
   	Obtain projection entity handles as ProSelection structures
\* =============================================================== */

  status = UserSelectProjectionEntities(&proj_ents);
  ERROR_CHECK("UserSelectrojectionEntities", "UserSectionPointBuild", status);

/* =============================================================== *\
    Project reference edges onto section
\* =============================================================== */

  for (i = 0; i < 2; i++)
    {
      status = ProSectionEntityFromProjection(section, proj_ents[i], &proj_ids[i]);
      ERROR_CHECK("ProSectionEntityFromProjection", "UserSectionPointBuild", status);
      if (status != PRO_TK_NO_ERROR)
	return(status);
    }
  
/* =============================================================== *\
    Create section csys from edges, and obtion transformation 
	matrix between sketch plane csys and section csys
\* =============================================================== */
  
  status = ProSectionEntityGet(section, proj_ids[0], (Pro2dEntdef **)&btm_linedef);
  ERROR_CHECK("ProSectionEntityGet", "UserSectionPointBuild", status);
  
  for (i = 0; i < 2; i++)
    {
      matrix_data.x_axis[0][i] = btm_linedef->end1[i];
      matrix_data.x_axis[1][i] = btm_linedef->end2[i];
      matrix_data.x_axis[i][2] = 0.0; 
    }
  
  status = ProSectionEntityGet(section, proj_ids[1], (Pro2dEntdef **)&left_linedef);
  ERROR_CHECK("ProSectionEntityGet", "UserSectionPointBuild", status);
  
  for (i = 0; i < 2; i++)
    {
      matrix_data.y_axis[0][i] = left_linedef->end1[i]; 
      matrix_data.y_axis[1][i] = left_linedef->end2[i];
      matrix_data.y_axis[i][2] = 0.0; 
    }
  
  status = ProSectionLocationGet(section, matrix_data.sk_mtrx);
  ERROR_CHECK("ProSectionLocationGet", "UserCreateTrfMatrix", status);
  
  status = ProSelectionCopy(sketch_refs[0], &(matrix_data.sk_plane));
  ERROR_CHECK("ProSelectionCopy", "UserSectionPointBuild", status) ;
  
  status = UserCreateTrfMatrix(&matrix_data);
  ERROR_CHECK("UseCreateTrfMatrix", "UserSectionPointBuild", status);

/* =============================================================== *\     
     Obtain offset values from projection entities
\* =============================================================== */
  
  status = UserSelectOffsetDistances(offsets);
  ERROR_CHECK("UserSelectOffsetDistances", "UserSectionPointBuild", status);
  
/* =============================================================== *\
     Add the required point(s)
     Currently only one point is added 
     This may be extended to add any number of points
\* =============================================================== */
  
  point.type    = PRO_2D_POINT;
  point.pnt[0] = 100; 
  point.pnt[1] = 100; 
  
  ProUtil2DPointTrans(matrix_data.sec_trf, point.pnt, point.pnt ); 

  status = ProSectionEntityAdd (section, (Pro2dEntdef*)&point, &point_id);
  ERROR_CHECK("UserSectionPointBuild - 1", "UserSectionPointBuild", status);

/* =============================================================== *\
   	Dimension, Solve and regenerate the section
\* =============================================================== */

  status = ProSecerrorAlloc(&sec_errors);
  ERROR_CHECK("ProSecerrorAlloc", "UserSectionPointBuild", status);
  
  status = ProSectionAutodim(section, &sec_errors);
  
  if (status != 0)
    {    
      UserSecerrorPrint (  &sec_errors );
      return status; 
    }
  
  status = ProSectionRegenerate(section, &sec_errors);
  if (status != 0)
    {
      UserSecerrorPrint (  &sec_errors );
      return status; 
    }
  
  status = ProSelectionFree(&(matrix_data.sk_plane));
  ERROR_CHECK("ProSelectionFree", "UserSectionPointBuild", status);
  
  free(temp1);
  free(temp2);

  temp1 = NULL;
  temp2 = NULL; 
  
  return(status);
}

/* Purpose : To print the Section errors and then free memory */ 
ProError UserSecerrorPrint ( ProWSecerror *section_errors )
{
  ProError status; 
  ProMsg error_message;
  char error_message_s[PRO_PATH_SIZE];
  int error_count; 
  int n_sec, error_id; 
  
  status = ProSecerrorCount ( section_errors, &n_sec ); 
  ERROR_CHECK (" ProSecerrorCount", "UserSecerrorPrint", status ); 
  
  ProTKPrintf("Number of errors in ProWSecerror = %d \n",n_sec ); 
  
  if ( status == PRO_TK_NO_ERROR )
    {
      for ( error_count = 0; error_count < n_sec; error_count++ )
	{
	  status = ProSecerrorMsgGet ( *section_errors, error_count, error_message);
	  ERROR_CHECK (" ProSecerrorMsgGet", "UserSecerrorPrint", status ); 
	  if ( status == PRO_TK_NO_ERROR )
	    {
	      status = ProSecerrorItemGet ( *section_errors, error_count, &error_id);
	      ERROR_CHECK (" ProSecerrorItemGet", "UserSecerrorPrint", status ); 
	      if ( status == PRO_TK_NO_ERROR )
		{
		  ProWstringToString (error_message_s, error_message);
		  ProTKPrintf(" %s : Problem ID : %d \n", error_message_s, error_id );
		}
	    }
	}
    }
  status = ProSecerrorFree ( section_errors ); 
  ERROR_CHECK (" ProSecerrorFree", "UserSecerrorPrint", status ); 
  
  return status; 
}
/*===============================================================*\

  FUNCTION: UserSweepSectionAdd
  ProError UserSweepSectionAdd ( ProSection ); 
  PURPOSE:  Creates a 2D sketch for sweep section 

\*===============================================================*/
ProError UserSweepSectionAdd ( ProSection section_here )
{
  Pro2dLinedef 		line; 
  ProError 		status; 
  int 			line_id[4]; 
  int 			cline_id1, cline_id2; 
  
  ProSelection          *proj_ents;
  int 			proj_ids[2];
  Pro2dLinedef          *left_linedef, *btm_linedef;
  
  ProName section_name; 
  
  ProWSecerror section_errors; 
  int n_sec; 
  ProMsg error_message;  
  char error_message_s[100];
  
  int i, error_id; 

  status = ProSecerrorAlloc ( &section_errors ); 
  ERROR_CHECK (" ProSecerrorAlloc", "UserSweepSectionAdd", status ); 
  
  {
    /* Adding Projection Entities => Specific to C/S in Sweep */ 

    /*---------------------------------------------------------------*\
      Get the projection entity handles as ProSelection structures.
      \*---------------------------------------------------------------*/
  
    status = UserSelectProjectionEntities (&proj_ents);
    ERROR_CHECK (" UserSelectProjectionEntities", "UserSweepSectionAdd", status ); 
    if (status != PRO_TK_NO_ERROR) return status;
  
    /*---------------------------------------------------------------*\
      Project the reference edges onto the section.
      \*---------------------------------------------------------------*/
  
    for (i = 0; i < 2; i++)
      {
	status = ProSelectionVerify ( proj_ents[i] ); 
	ERROR_CHECK (" ProSelectionVerify", "UserSweepSectionAdd", status ); 
        if (status != PRO_TK_NO_ERROR) return status;

	status = ProSectionEntityFromProjection ( section_here, proj_ents[i],
						  &proj_ids[i]);
	ERROR_CHECK (" ProSectionEntityFromProjection", "UserSweepSectionAdd", status ); 
        if (status != PRO_TK_NO_ERROR) return status;
      
      }

    status = ProSectionEntityGet ( section_here, proj_ids[0],
				   (Pro2dEntdef**)&left_linedef);
    ERROR_CHECK (" ProSectionEntityGet", "UserSweepSectionAdd", status ); 
    if (status != PRO_TK_NO_ERROR) return status;

    status = ProSectionEntityGet ( section_here, proj_ids[1],
				   (Pro2dEntdef**)&btm_linedef);
    ERROR_CHECK (" ProSectionEntityGet", "UserSweepSectionAdd", status ); 
    if (status != PRO_TK_NO_ERROR) return status;

  }

  line.type = PRO_2D_LINE;
  line.end1[0] = 0;
  line.end1[1] = 0;
  line.end2[0] = 100; 
  line.end2[1] = 0; 

  status = ProSectionEntityAdd ( section_here, (Pro2dEntdef*)&line, &line_id[0] ) ;
  ERROR_CHECK (" ProSectionEntityAdd", "UserSweepSectionAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;
	  
  line.type = PRO_2D_LINE;
  line.end1[0] = 100;
  line.end1[1] = 0;
  line.end2[0] = 100; 
  line.end2[1] = 100; 

  status = ProSectionEntityAdd ( section_here, (Pro2dEntdef*)&line, &line_id[1] ) ;
  ERROR_CHECK (" ProSectionEntityAdd", "UserSweepSectionAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;


  line.type = PRO_2D_LINE;
  line.end1[0] = 100;
  line.end1[1] = 100;
  line.end2[0] = 0; 
  line.end2[1] = 100; 
  
  status = ProSectionEntityAdd ( section_here, (Pro2dEntdef*)&line, &line_id[2] ) ;
  ERROR_CHECK (" ProSectionEntityAdd", "UserSweepSectionAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;
  
  line.type = PRO_2D_LINE;
  line.end1[0] = 0;
  line.end1[1] = 100;
  line.end2[0] = 0; 
  line.end2[1] = 0; 

  status = ProSectionEntityAdd ( section_here, (Pro2dEntdef*)&line, &line_id[3] ) ;
  ERROR_CHECK (" ProSectionEntityAdd", "UserSweepSectionAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;
	  
  { 
    double epsilon; 
    status = ProSectionEpsilonGet( section_here, &epsilon );
    ERROR_CHECK (" ProSectionEpsilonGet", "UserSweepSectionAdd", status ); 

    ProTKPrintf ("The current epsilon  is %f\n", epsilon ); 
  } 

  status = ProSectionEpsilonSet( section_here, 0.1 );
  ERROR_CHECK (" ProSectionEpsilonSet", "UserSweepSectionAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;

  status = ProSectionAutodim ( section_here, &section_errors ); 
  ERROR_CHECK (" ProSectionAutodim", "UserSweepSectionAdd", status ); 
  
  if ( status != PRO_TK_NO_ERROR )
    {
      UserSecerrorPrint ( &section_errors ); 
      return status; 
    } 
  
  
  status = ProSectionRegenerate ( section_here, &section_errors ); 
  ERROR_CHECK (" ProSectionRegenerate", "UserSweepSectionAdd", status ); 
  
  if ( status != PRO_TK_NO_ERROR )
    {
      UserSecerrorPrint ( &section_errors ); 
      return status; 
    }
  
  return ( status ); 
  
}

/*===============================================================*\

  FUNCTION: UserSweepSpineAdd
  ProError UserSweepSpineAdd ( ProSection, ProSelection * ); 
  PURPOSE:  Creates a 3D trajectory for sweep section 

\*===============================================================*/
ProError UserSweepSpineAdd (ProSection section_here, 
			    ProSelection *sketch_refs )
{
  ProSelection          *proj_ents;
  int                    status, i, num_errors, err_counter, proj_ids[2];
  int                    ctr_line_id, rt_line_id, lt_line_id,
   top_line_id, btm_line_id;
  int                    upper_arc_id, lower_arc_id, ent_id[1],
    c_ent_id[2], proj_ent_id[2];
  int                    ll_dim_id, tl_dim_id, ua_dim_id, la_dim_id,
    cl_dim_id, proj_dim_id[2];
  ProWSecerror           sec_errors;
  Pro2dLinedef           line;
  Pro2dClinedef          c_line;
  Pro2dLinedef          *left_linedef, *btm_linedef;
  ProSectionPointType    pt_type[1], proj_pt_type[2];
  Pro2dArcdef            arc;
  Pro2dPnt               place_pnt;
  ProMsg                 wmsg;
  char                   msg[PRO_PATH_SIZE];
  double                 offsets[2];
  Matrix_data            matrix_data;
  
  int row, column; 

  /* initializing the matrices */ 

  for ( row = 0; row < 4; row++ ) 
    {
      for ( column  = 0 ; column < 4; column++ ) 
	{
	  matrix_data.sec_trf[row][column] = 0.0; 
	  matrix_data.sk_mtrx[row][column] = 0.0; 
	}
    }
  
  /*---------------------------------------------------------------*\
  Get the projection entity handles as ProSelection structures.
  \*---------------------------------------------------------------*/
  
  status = UserSelectProjectionEntities (&proj_ents);
  ERROR_CHECK (" UserSelectProjectionEntities", "UserSweepSpineAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;
  
  /*---------------------------------------------------------------*\
  Project the reference edges onto the section.
  \*---------------------------------------------------------------*/
  
  for (i = 0; i < 2; i++)
    {
      status = ProSelectionVerify ( proj_ents[i] ); 
      ERROR_CHECK (" ProSelectionVerify", "UserSweepSpineAdd", status ); 
      if (status != PRO_TK_NO_ERROR) return status;

      status = ProSectionEntityFromProjection ( section_here, proj_ents[i],
						&proj_ids[i]);
      ERROR_CHECK (" ProSectionEntityFromProjection", "UserSweepSpineAdd", status ); 
      
      if (status != PRO_TK_NO_ERROR) return status;
    }
  
  /*---------------------------------------------------------------*\
    Create the section coordinate system from the edges. Get the 
    transformation matrix between the sketch plane coordinate system
    and the section coordinate system.
  \*---------------------------------------------------------------*/
  
  status = ProSectionEntityGet ( section_here, proj_ids[0],
				 (Pro2dEntdef**)&btm_linedef);
  ERROR_CHECK (" ProSectionEntityGet", "UserSweepSpineAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;
  
  for (i = 0; i < 2; i++)
    {
      matrix_data.x_axis[0][i] = btm_linedef->end1[i];
      matrix_data.x_axis[1][i] = btm_linedef->end2[i];
      matrix_data.x_axis[i][2] = 0.0; 
    }
  
  status = ProSectionEntityGet ( section_here, proj_ids[1],
				 (Pro2dEntdef**)&left_linedef);
  ERROR_CHECK (" ProSectionEntityGet", "UserSweepSpineAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;
  
  for (i = 0; i < 2; i++)
    {
      matrix_data.y_axis[0][i] = left_linedef->end1[i]; 
      matrix_data.y_axis[1][i] = left_linedef->end2[i];
      matrix_data.y_axis[i][2] = 0.0; 
    }
  
  status = ProSectionLocationGet ( section_here, matrix_data.sk_mtrx);
  ERROR_CHECK (" ProSectionLocationGet", "UserSweepSpineAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;
  
  status = ProSelectionCopy (sketch_refs[0], &(matrix_data.sk_plane));
  ERROR_CHECK (" ProSelectionCopy", "UserSweepSpineAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;
  
  status = UserCreateTrfMatrix (&matrix_data);
  ERROR_CHECK (" UserCreateTrfMatrix", "UserSweepSpineAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;
  
  /*---------------------------------------------------------------*\
    Get the offset values from the projection entities.
  \*---------------------------------------------------------------*/
  
  status = UserSelectOffsetDistances (offsets);
  ERROR_CHECK (" UserSelectOffsetDistances", "UserSweepSpineAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;
  
  ProTKPrintf("Offset Distances in main are offset[0] = %f : offset[1]  = %f\n", 
	 offsets[0], offsets[1]);
  
  /*---------------------------------------------------------------*\
    Add the left vertical line.
  \*---------------------------------------------------------------*/
  
  line.type = PRO_2D_LINE;
  
  line.end1[0] = offsets[1];
  line.end1[1] = offsets[0];
  line.end2[0] = offsets[1];
  line.end2[1] = offsets[0] + 50.0;
 
  ProUtil2DPointTrans (matrix_data.sec_trf, line.end1, line.end1);
  ProUtil2DPointTrans (matrix_data.sec_trf, line.end2, line.end2);
  
  status = ProSectionEntityAdd ( section_here, (Pro2dEntdef*)&line,
				 &lt_line_id);
  ERROR_CHECK (" ProSectionEntityAdd", "UserSweepSpineAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;

  /*---------------------------------------------------------------*\
    Solve and regenerate the section.
  \*---------------------------------------------------------------*/
  
  status = ProSecerrorAlloc (&sec_errors);
  ERROR_CHECK (" ProSecerrorAlloc", "UserSweepSpineAdd", status ); 
  
  status = ProSectionEpsilonSet( section_here, 0.1 );
  ERROR_CHECK (" ProSectionEpsilonSet", "UserSweepSpineAdd", status ); 
  if (status != PRO_TK_NO_ERROR) return status;
  
  status = ProSectionAutodim ( section_here, &sec_errors);
  ERROR_CHECK (" ProSectionAutodim", "UserSweepSpineAdd", status ); 
  
  if (status != PRO_TK_NO_ERROR)
    {
      UserSecerrorPrint ( &sec_errors ); 
      return status; 
    }
  
  status = ProSectionRegenerate ( section_here, &sec_errors);
  ERROR_CHECK (" ProSectionRegenerate", "UserSweepSpineAdd", status ); 
  
  if (status != PRO_TK_NO_ERROR)
    {
      UserSecerrorPrint ( &sec_errors ); 
      return status; 
    }
  status = ProSelectionFree (&(matrix_data.sk_plane));
  ERROR_CHECK (" ProSelectionFree", "UserSweepSpineAdd", status ); 
  
  return (status);
}

